package com.chongyahhh.security.security.common;

import com.chongyahhh.security.security.handler.JsonAuthenticationFailureHandler;
import com.chongyahhh.security.security.handler.JsonAuthenticationSuccessHandler;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @Author chongyahhh
 * 通用过滤器
 * 通过设置不同认证处理器和拦截url来进行不同的验证
 */
public class CommonAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
    // 认证处理器
    private AuthenticationProcessor processor;

    private boolean postOnly = true;

    public CommonAuthenticationFilter(String url, AuthenticationProcessor processor) {
        // 设置拦截url
        super(new AntPathRequestMatcher(url, "POST"));
        // 设置认证处理器
        this.processor = processor;
        // 这里继续执行拦截器链
        super.setContinueChainBeforeSuccessfulAuthentication(true);
        // 这两个也可以在loginForm()后设置
        // 设置认证失败处理入口
        setAuthenticationFailureHandler(new JsonAuthenticationFailureHandler());
        // 设置认证成功处理入口
        setAuthenticationSuccessHandler(new JsonAuthenticationSuccessHandler());
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        if (this.postOnly && !request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException("请确认请求方式");
        }
        // 认证前置处理
        Authentication authRequest = processor.preAuthentication(request, response);
        // 认证
        Authentication authenticate = this.getAuthenticationManager().authenticate(authRequest);
        // 先将用户信息存到 session 中，虽然之后 security 会再存一次，但不影响
        SecurityContextHolder.getContext().setAuthentication(authenticate);
        // 认证后置处理
        processor.postAuthentication(request, response);

        return authenticate;
    }

}
